//====================================================================
//文件名称：ds18b20.c
//功能概要：DS18B20软件构件源文件（单点测温）
//技术参考：DS18B20数据手册
//版权所有：江苏电子-索明何
//版本更新：2023-03-25  V1.0
//====================================================================
//1.包含本软件构件头文件
#include  "ds18b20.h" 

//2.仅用于本文件的全局变量和内部函数的声明
static void ds18b20_reset(void);                //复位DS18B20
static void ds18b20_write(uint8 write_data);    //向DS18B20写入1字节数据
static uint8 ds18b20_read(void);                //从DS18B20读取1字节数据

//3.对外接口函数的定义与实现
//====================================================================
//函数名称：ds18b20_get_temperature
//函数功能：获取DS18B20温度绝对值的10倍值（如12.5℃、-12.5℃对应返回125）
//函数参数：*flag: 用于传回温度正负标志值（0表示正值，1表示负值）
//               （可用实参变量的地址作为函数实参，使实参变量获取温度正负标志值）
//函数返回：DS18B20温度绝对值的10倍值
//====================================================================
uint16 ds18b20_get_temperature(uint8 *flag)
{
    //1.定义局部变量，并给有关变量赋初值
    uint16 temp = 0;
	
    //2.启动温度转换	
    ds18b20_reset( );              //DS18B20复位
    ds18b20_write(0xCC);           //跳过ROM
    ds18b20_write(0x44);           //写RAM，启动温度转换
    Delay_ms(5);           	       //延时5ms，等待温度转换完成
	
    //3.读取并返回温度绝对值
    ds18b20_reset( );              //DS18B20复位
    ds18b20_write(0xCC);           //跳过ROM
    ds18b20_write(0xBE);           //读取RAM
    temp = ds18b20_read( );        //读取低8位数据
    temp |= (ds18b20_read( )<<8);  //读取高8位数据，并与低8位数据合并
	
    if((temp&0xF800) == 0)         //若两字节数据高5位为00000，则表示温度为正值 
    {  
        *flag = 0;                 //温度正负标志清零，表示温度为正值		
    }
    else                           //若两字节数据高5位为11111，则表示温度为负值
    {
        *flag = 1;                 //温度正负标志置1，表示温度为负值
        temp = 65536-temp;         //计算出两字节数据（负数补码）对应的负数绝对值
    }	
		
    return  (temp*0.625);          //0.0625表示xx，0.625表示xx.x，6.25表示xx.xx（摄氏度）
}

//4.内部函数的定义与实现
//====================================================================
//函数名称：ds18b20_reset
//函数功能：复位DS18B20
//函数参数：无
//函数返回：无
//====================================================================
static void ds18b20_reset(void)
{
    gpio_init(DS18B20, GPIO_OUT, 0);   //将总线对应的MCU引脚设为输出，输出低电平
    Delay_us(500);                     //延时500us（480~960us）
	
    gpio_set(DS18B20, 1);              //释放总线，等待DS18B20应答和总线被拉至高电平
    Delay_us(300);                     //延时300us
}

//====================================================================
//函数名称：ds18b20_write
//函数功能：向DS18B20写入1字节数据（先低位，后高位）
//函数参数：data：待写入的1字节数据
//函数返回：无
//====================================================================
static void ds18b20_write(uint8 write_data)
{
    uint8  i;
    gpio_init(DS18B20, GPIO_OUT, 0);              //将总线对应的MCU引脚设为输出，输出低电平
	
    for(i=0; i<8; i++)
    {				
        gpio_set(DS18B20, 0);                     //使总线为低电平
        Delay_us(2);                              //延时2us	
			
        gpio_set(DS18B20, BGET(write_data, i));   //向总线写入1位数据
        Delay_us(60);                             //延时60us，等待DS18B20采样
			
        gpio_set(DS18B20, 1);                     //使总线为高电平，释放总线
        Delay_us(2);                              //延时2us（写入周期之间至少相隔1us）
    }
}

//====================================================================
//函数名称：ds18b20_read
//函数功能：从DS18B20总线上读取1字节数据（先低位，后高位）
//函数参数：无
//函数返回：从DS18B20总线上读取到的1字节数据
//====================================================================
static uint8 ds18b20_read(void)
{
    uint8 i, read_data = 0;
    for(i=0; i<8; i++)
    {
        gpio_init(DS18B20, GPIO_OUT, 0);   //将总线对应的MCU引脚设为输出，输出低电平
        Delay_us(2);                       //延时2us（至少1us）		
			
        gpio_set(DS18B20, 1);              //使总线为高电平，释放DQ线
        Delay_us(8);                       //延时8us 		
			
        gpio_init(DS18B20, GPIO_IN, 0);    //将总线对应的MCU引脚设为输入
        gpio_pull(DS18B20, PULL_UP);       //使能MCU引脚内部上拉电阻，以便读取总线数据
        if(gpio_get(DS18B20) == 1)         //从总线上读取1位数据
            BSET(read_data, i);
        Delay_us(50);                      //延时50us
    }
		
    return  read_data;                     //返回从总线上读取到的1字节数据
}
